#include "hpcr_types.h"
#include "core/hpcr_list.h"
#include "core/hpcr_memory.h"

void hpcr_memory_pool_init(hpcr_memory_pool_t *mp, void *buffer, hpcr_size_t size)
{
    mp->buffer = buffer;
    mp->size = size;
    hpcr_list_init(&mp->node);
    hpcr_list_init(&mp->use);
    hpcr_list_init(&mp->free);
    hpcr_memory_header_t *mh = (hpcr_memory_header_t *)buffer;
    mh->size = size;
    hpcr_list_push(&mp->free, &mh->item);
}

// Memory的分配采用的是尾部分配法，选取一块比所需内存大的最小的内存空间，这样可以防止内存碎片化
// 只允许一次分配，不允许二次分配
void *hpcr_memory_alloc(hpcr_memory_pool_t *mp, hpcr_size_t size)
{
    // 4字节对齐
    hpcr_size_t need_remain_space = sizeof(hpcr_memory_header_t) * 2 + (size + 3) / 4 * 4;
    hpcr_list_node_t *item, *tmp_ptr = NUL;
    hpcr_size_t biger_min_size = -1, tmp_size;
    item = mp->free.head.next;
    while (item != &mp->free.tail)
    {
        tmp_size = MemorySize(item);
        // 如果空间正好，直接退出循环
        if (tmp_size == need_remain_space)
        {
            tmp_ptr = item;
            biger_min_size = tmp_size;
            break;
        }

        // 需要找更合适的小空间
        if (tmp_size > need_remain_space && tmp_size < biger_min_size)
        {
            tmp_ptr = item;
            biger_min_size = tmp_size;
        }

        item = item->next;
    }

    // 没有合适的空间，分配失败
    if (tmp_ptr == NUL)
    {
        return NUL;
    }

    // 从尾部开始分配
    hpcr_memory_header_t *res = (hpcr_memory_header_t *)tmp_ptr;

    res->size -= (need_remain_space - sizeof(hpcr_memory_header_t));

    // 计算从尾部开始分配的最终指针位置
    tmp_ptr = (hpcr_list_node_t *)((hpcr_uint8_t *)tmp_ptr + res->size);
    hpcr_memory_header_t *dst = (hpcr_memory_header_t *)tmp_ptr;
    dst->size = need_remain_space - sizeof(hpcr_memory_header_t);

    hpcr_list_push(&mp->use, &dst->item);

    return MemorySpace(tmp_ptr);
}

// 释放内存
bool hpcr_memory_free(hpcr_memory_pool_t *mp, void *ptr)
{
    hpcr_list_node_t *item = (hpcr_list_node_t *)MemoryItem(ptr);
    // 首先从mp->use中释放
    hpcr_list_remove(item);
    // 然后顺序插入到mp->free中
    hpcr_list_node_t *pre = mp->free.head.next, *next = pre->next;
    while (next->next != NUL && (hpcr_ptr_t)item > (hpcr_ptr_t)next)
    {
        pre = next;
        next = next->next;
    }

    bool isMerge = false;

    // 与前节点尝试内存合并
    if ((hpcr_ptr_t)pre + ((hpcr_memory_header_t *)pre)->size == (hpcr_ptr_t)item)
    {
        hpcr_memory_header_t *tmp = (hpcr_memory_header_t *)item;
        ((hpcr_memory_header_t *)pre)->size += tmp->size;
        item = pre;
        isMerge = true;
    }

    // 与后节点尝试内存合并
    hpcr_memory_header_t *tmp = (hpcr_memory_header_t *)item;
    if (next != &(mp->use.tail) && (hpcr_ptr_t)item + tmp->size == (hpcr_ptr_t)next)
    {
        hpcr_list_remove(next);
        tmp->size += ((hpcr_memory_header_t *)next)->size;
        isMerge = true;
    }

    if (isMerge)
    {
        return true;
    }

    hpcr_list_insert_after(pre, item);

    return true;
}